package com.edroid.plugin;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.security.MessageDigest;

public final class PluginVerifyer {

	private final static int MAKER_VER = 1;
	private final static int SECURITY_LENGTH = 128;
	private final static long MD5_KEY = 0x20090525;
	private final static int ENDHDR = 22;
	private final static int ENDOFF = 16;
	
	
	
	public static void verify(InputStream is) {
		
	}

	/**
	 * 校验插件，并获取插件信息
	 * 
	 * @param pluginFilePath
	 * @return 插件信息
	 * 
	 * @throws Exception 抛出异常表示检验失败
	 */
	public static PluginInfo verify(String pluginFilePath) throws Exception {
		RandomAccessFile tfile = new RandomAccessFile(pluginFilePath, "r");
		BufferedInputStream bis;

//		int maker_ver_number_buffer_len = 4;
		byte[] buf = new byte[4];
		tfile.seek(tfile.length() - 4);
		tfile.read(buf);
		
		long plugin_maker_ver_number = get32(buf, 0);
		if (plugin_maker_ver_number != MAKER_VER) {
			tfile.close();
			new File(pluginFilePath).delete();
			throw new Exception("JarFormatNotSupportException");
		}
		
		byte[] endBuff = new byte[ENDHDR];
		tfile.seek(tfile.length() - ENDHDR - 4);
		tfile.read(endBuff);

		long cenOffset = get32(endBuff, ENDOFF);
		tfile.seek(cenOffset - SECURITY_LENGTH + 16);
		long security_data_len = tfile.length() - (cenOffset - SECURITY_LENGTH + 16);
		byte[] security_data_buff = new byte[(int) security_data_len];
		tfile.read(security_data_buff);

		byte[] md5KeyBuff = new byte[4];
		set32(md5KeyBuff, 0, MD5_KEY);
		MessageDigest md5 = MessageDigest.getInstance("MD5");
		md5.update(security_data_buff);
		md5.update(md5KeyBuff);
		byte[] digest = md5.digest();
		String md5String = getHexString(digest, 0, digest.length);
		md5 = MessageDigest.getInstance("MD5");
		md5.update(md5String.getBytes());
		digest = md5.digest();

		tfile.seek(cenOffset - SECURITY_LENGTH);
		byte[] oldDigest = new byte[16];
		tfile.read(oldDigest);
		for (int i = 0; i < digest.length; i++) {
			if (digest[i] != oldDigest[i])
				throw new SecurityException("IllegalJarFileException");
		}

		byte[] verBuff = new byte[4];
		byte[] nameLenBuff = new byte[2];
		tfile.read(verBuff);
		tfile.read(nameLenBuff);

		long pluginVerNumber = get32(verBuff, 0);
		int pluginNameLen = get16(nameLenBuff, 0);

		byte[] nameBuff = new byte[pluginNameLen];
		tfile.read(nameBuff);
		tfile.close();

		PluginInfo info = new PluginInfo();
		info.pluginName = new String(nameBuff);
		info.pluginVerNumber = pluginVerNumber;

		return info;
	}

	private static int get16(byte b[], int off) {
		return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8);
	}

	private static long get32(byte b[], int off) {
		return get16(b, off) | ((long) get16(b, off + 2) << 16);
	}

	private static void set32(byte[] b, int offset, long value) {
		b[offset] = (byte) (value & 0xFF);
		b[offset + 1] = (byte) ((value >> 8) & 0xFF);
		b[offset + 2] = (byte) ((value >> 16) & 0xFF);
		b[offset + 3] = (byte) ((value >> 24) & 0xFF);
	}

	private static String getHexString(byte[] b, int offset, int len) {
		String result = "";
		for (int i = offset; i < offset + len; i++) {
			result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
		}
		return result;
	}
	
	public static void main(String[] args) {
		try {
			verify("E:\\workspaces\\openmoposdk\\push\\Make\\mopopush.jar");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
